package client;

import ihm.Conversation;
import ihm.FenetrePrincipale;
import ihm.ThreadConversation;

import java.awt.HeadlessException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;

import javax.swing.JOptionPane;

/**
 * Connexion au serveur lors de la connexion d'un utilisateur
 * 
 */
public class CommunicationClient extends Thread
{
	/*
	 * connection indique si le client est authentifié sur le serveur
	 */

		public boolean connection=false;
		private boolean var;		
		private ArrayList<Conversation> conversations= new ArrayList<Conversation>();
		private ArrayList<String> amis= new ArrayList<String>();
		private ArrayList<String> amisDeco=new ArrayList<String>();
		private HashMap <String , String> statuts= new HashMap<String,String>();
		private HashMap <String , String> pseudos= new HashMap<String,String>();
		private ArrayList<Message> messages=new ArrayList<Message>();


		private String email,mDp, mess, nam, fName;


		private int action;
		private Socket comm = null;
		private InputStream is = null;
		private String statut,pseudo;	

		private BufferedReader _in; // pour gestion du flux d'entrée
		private int existe=2;
		private int dejaAmi=2;
		private int pasEncoreDemande=2;
		private int existe2=2;

		private String demandeur="";
		private CommunicationClientEnvoie comE;

		private boolean demandeurFini=false;
		char charCur[] = new char[1];
		private String amiD;
		private String pseud;
		private String ami;
		private String stat;


	/**
	  * 
	  * @return true: connection au serveur réussie 
	  * 		   false: connection non établie
	  * @throws IOException 
	  * @throws UnknownHostException 
	  */
	public CommunicationClient(String name, String firstName, String mail,String mDep,int act) throws UnknownHostException, IOException
	{
		nam=name;
		fName=firstName;
	  	email=mail;
	   	mDp=mDep;
	   	action=act;
   		comm = new Socket("localhost",18888); 
   		//comm = new Socket("upgrad.esil.univ-mrs.fr/",8888);
   		comE=new CommunicationClientEnvoie(comm, nam, fName, email, mDp);
   		comE.start();
   		statut="En ligne";
	}
	

	/** Methode qui se lance dès que le thread.start() **/
	public void run()
	{
	  	try
	   	{
    		while(true)
    		{    		
		    	is = comm.getInputStream();	    		
			    _in = new BufferedReader(new InputStreamReader(is));
			    ami="";amiD="";stat="";pseud="";
			    

		    	if(_in.read(charCur, 0, 1) != -1 )
		    	{	
		    		//DEMANDE DE CONNEXION

		    		 if(charCur[0]=='C'){
		    			 demandeConnexion();
		    		 }
		    		//ACTUALISATION DU STATUT
		    		if(charCur[0]=='T'){		
		    			actualisationStatut();
		    		}
		    		
		    		//ACTUALISATION DU PSEUDO
		    		if(charCur[0]=='P'){
		    			actualisationPseudo();
		    		}
		    		//ACTUALISATION DE LA LISTE D'AMIS  
		    		if(charCur[0]=='A'){
		    			actualisationListe();		
		    		}
		    		//ENVOI DE MESSAGE EN CONVERSATION
		    		if(charCur[0]=='M'){
		    			envoiMessage();		   
		    		}//fin if(=M)	    			    

		    		//DEMANDE D'INSCRIPTION
		    		if(charCur[0]=='I'){
		    			demandeInscription();
			    	}
		    		//DEMANDE D'AMI
		    		if(charCur[0]=='D'){	
		    			demandeAmi();			 
			    	}
		    		//VERIFICATION DES DEMANDES A LA CONNEXION
		    		if(charCur[0]=='V'){
		    			verificationDemandes();
			    	}
		    		action=0;
		    		//RECUPERER DES DEMANDES A LA CONNEXION
		    		if(charCur[0]=='R'){
		    			recuperationDemandes(); 
			    	}
		    		
		    		// ACCEPTER LA DEMANDE
		    		if(charCur[0]=='O'){
		    			acceptationDemande();
			    	}
		    		
		    		// SUPPRIMER DEMANDE
		    		if(charCur[0]=='S'){	
		    			supprimerDemande();
			    	}
		    		
		    		// AFFICHER LISTE MESSAGES
		    		if(charCur[0]=='E'){	
		    			actualiseListeMessages();
			    	}
		    	}
			}//fin while(true)	  	
    	}catch(Exception e){System.err.println("Exception " + e.toString());}
	    finally
	    {
	    	if (is!=null)
	    	try 
	    	{
	    		is.close();
	    	} catch (IOException e) {e.printStackTrace();}
	    	if (comm!=null)
	    	try 
	    	{
	    		comm.close();
			} catch (IOException e) {e.printStackTrace();}
			}	    
	}//fin run()
	

	/** Methode qui demande la connexion **/
	private void demandeConnexion() throws IOException 
	{		
		if(_in.read(charCur, 0, 1) != -1)
		{
			if(charCur[0]=='1')
			{	connection=true;
				new FenetrePrincipale(this);
				//on récupère la liste des connectés
				while(_in.read(charCur, 0, 1) != -1)
				{	
					if(charCur[0]!='\u0000')
					{	if(charCur[0]!='\n' && amiD=="")//on récupère la liste des connectés avec leurs pseudos
						{	if(charCur[0]!=';')
							{	if(charCur[0]!=',' && stat=="" )
				        			ami += charCur[0];
				        		else
				        		{	if(stat==""){
				        				_in.read(charCur, 0, 1);
				        				stat=stat+charCur[0];}
				        			else
				        				stat=stat+charCur[0];
				        		}
				        	}
				        	else
				        	{	if(ami!="" && stat!="")
				        		{	String[] s=new String[2];
				        			s=stat.split(",");
				        			stat=s[0];pseud=s[1];
				        			amis.add(ami);
				        			this.statuts.put(ami, stat);
				        			this.pseudos.put(ami, pseud);
				        			ami="";
				        			stat="";
				        		}			    			
				        	}	
						}
						else //on récupère la liste des amis déconnectés
						{ 
							if(amiD==""){
									_in.read(charCur, 0, 1);
								if(charCur[0]=='0') 
									break;
								else
									amiD=amiD+charCur[0];
							}
							else
								amiD=amiD+charCur[0];		    										    								
						}
					}
					else
					{	String[]amisD=amiD.split(",");
						for(int i=0;i<amisD.length;i++){
							amisDeco.add(amisD[i]);
						}
						break;}
			     }//fin while				
			}
			else
				connection=false;
			}
		}//fin demandeConnexion()
	
	
	/** Methode qui actualise le statut **/
	private void actualisationStatut() throws IOException 
	{
		String mailAmi="",statut="";
		while(_in.read(charCur, 0, 1) != -1){
			if(charCur[0]!='\u0000'){
			      if(charCur[0]!=';' && statut=="")
			        mailAmi += charCur[0];
			       else{
			        	if(statut==""){
			        		_in.read(charCur, 0, 1);
			        		statut=statut+charCur[0];}
			        	else
			        		statut=statut+charCur[0];
			        }
			}
			else{
				this.statuts.remove(mailAmi);
				this.statuts.put(mailAmi, statut);
				break;
			}
		}
	}//fin actualisationStatut()
		

	/** Methode qui actualise le pseudo **/
	private void actualisationPseudo() throws IOException 
	{
		String mailAmi="";
		pseudo="";
		while(_in.read(charCur, 0, 1) != -1){
			if(charCur[0]!='\u0000'){
			      if(charCur[0]!=';' && pseudo=="")
			        mailAmi += charCur[0];
			       else{
			        	if(pseudo==""){
			        		_in.read(charCur, 0, 1);
			        		pseudo=pseudo+charCur[0];}
			        	else
			        		pseudo=pseudo+charCur[0];
			        }
			}
			else{
				this.pseudos.remove(mailAmi);
				this.pseudos.put(mailAmi, pseudo);
				break;
			}
		}		
	}//fin actualisationPseudo()


	/** Methode qui actualise la liste d'amis**/
	private void actualisationListe() throws IOException 
	{
		ami="";
		String var="";
		_in.read(charCur, 0, 1);
		//cela signifie qu'un client vient de se connecter
		if (charCur[0]=='c')
		{
			while(_in.read(charCur, 0, 1) != -1 ){
		      	// on regarde si on arrive à la fin d'une chaine ...
		        if (charCur[0] != '\u0000' ){
		        		if(charCur[0]!=';'&& var=="")
		        			ami += charCur[0]; // ... si non, on concatène le caractère dans le message	
		        		else
		        		{	   			
		        			if(var==""){
			        			_in.read(charCur, 0, 1);
			        			var=var+charCur[0];}
		        			else
		        				var=var+charCur[0];
		        		}
		        }
		        else{
		        	String[]s=new String[2];
		        	s=var.split(";");
		        	amis.add(ami);
		        	amisDeco.remove(ami);
		        	this.statuts.put(ami, s[0]);
		        	this.pseudos.put(ami,s[1]);
		        	break;
		        }
			}
		}
		//cela signifie qu'un client vient de se déconnecter
	    else{
	    	while(_in.read(charCur, 0, 1) != -1 ){
	    		if (charCur[0] != '\u0000' )
	    			ami=ami+charCur[0];
	    		else{
	    			amis.remove(ami);
	    			amisDeco.add(ami);
	        		break;	
	        	}						        	
        	}
		}//fin while
	}// fin actualisationListe()

	
	/** Methode qui envoie un message instantane **/
	private void envoiMessage() throws IOException 
	{
		mess=""; String mailConvers="";
		while(_in.read(charCur, 0, 1) != -1)
		{
	      	// on regarde si on arrive à la fin d'une chaine ...
	        if ( charCur[0] != '\u0000' ){
	        	if(charCur[0]!=';' && mess.compareTo("")==0)
	                mailConvers += charCur[0]; // ... si non, on concatène le caractère dans le message				        	
	        	else{
    				 if(charCur[0]!=';')
    					 mess=mess+charCur[0];
    				 else{
    					 _in.read(charCur,0,1);
    					 mess=mess+charCur[0];
    				 }
	        	}
	        }//fin if charCur(0]!=; 
	        else{
		        	var=false;
		        	for(int i=0;i<conversations.size();i++)
		        	{
		        		if(conversations.get(i).getEmail().compareTo(mailConvers)==0){
		        			conversations.get(i).affichageTexte(mess, mailConvers);
		        			var=true;
		        		}
		        	}
		        	if(var==false){
		    			ThreadConversation th=new ThreadConversation(mailConvers, this);
		    			th.start();
		    			th.getConv().affichageTexte(mess, mailConvers);
		        	}
	    			break;
		        }					        
			}//fin while		
	}//fin envoiMessage()


	/** Methode qui demande l'inscription **/
	private void demandeInscription() throws HeadlessException, IOException 
	{
		if(_in.read(charCur, 0, 1) != -1)
		{	if(charCur[0]=='1')//resultat d'emailExistePas
			{	if(_in.read(charCur, 0, 1) != -1)			    					
	    		{	if(charCur[0]=='1')//resultat d'incrireClient
	    			{	    		
	    				/*FenetreConnexion fenC=new FenetreConnexion();
	    				fenC.setVisible(true);*/
	                    JOptionPane.showMessageDialog(null, "Votre inscription a bien ete enregistree !", "Message " +
	    			 		"d’information", JOptionPane.INFORMATION_MESSAGE);	                    
	    			}
	    		}
			}else 	JOptionPane.showMessageDialog(null, "Cet email existe deja","Message " +
            		"d’avertissement", JOptionPane.ERROR_MESSAGE);			    					    			
		}		
	}//fin demandeInscription()
		

	/** Methode qui demande en ami **/
	private void demandeAmi() throws IOException 
	{
		if(_in.read(charCur, 0, 1) != -1)
		{	if(charCur[0]=='1')// resultat1 verifAdrExiste 
			{					    				
				existe=1;			    				
			}else existe=0;
		}    		
		if(_in.read(charCur, 0, 1) != -1)
		{	if(charCur[0]=='1')//resultat2 verifAdrExiste
			{					    				
				dejaAmi=1;			    				
			}else dejaAmi=0;
		}
		if(_in.read(charCur, 0, 1) != -1)
		{	if(charCur[0]=='1')//resultat3 verifAdrExiste
			{					    				
				pasEncoreDemande=1;			    				
			}else pasEncoreDemande=0;
		}		
	}//fin demandeAmi()
	
	
	/** Methode qui verifie les demandes lors de la connexion **/
	private void verificationDemandes() throws IOException 
	{
		if(_in.read(charCur, 0, 1) != -1)
		{		
			if(charCur[0]=='1')//resultat verifierDemande
			{					    				
				existe2=1;			    				
			}else {existe2=0;}
		} 		
	}//fin verificationDemandes()
	
	
	/** Methode qui recupere les demandes **/
	private void recuperationDemandes() throws IOException 
	{		    			
		demandeur="";    			
		if(_in.read(charCur, 0, 1) != -1)
		{	
			while(charCur[0]!=-1) 
		    {
		      	// on regarde si on arrive à la fin d'une chaine ...
		        if (charCur[0] != '\u0000' && charCur[0] != '\n' && charCur[0] != '\r')
		        {						        	
					if(charCur[0]!=';')
		                demandeur += charCur[0]; // ... si non, on concatène le caractère dans le message
			        _in.read(charCur, 0, 1);
			       
		        }
		        else if(!demandeur.equalsIgnoreCase("")) // juste une vérification de principe
		        {
		        	break;
		        }
		        demandeurFini=true;
		    } 
		}		
	}// fin recuperationDemandes()
	
	
	/** Methode qui accepte la demande **/
	private void acceptationDemande() throws IOException 
	{
		if(_in.read(charCur, 0, 1) != -1)
		{		
			int ok;
			if(charCur[0]=='1')// resultat1 accepte demande
			{					    				
				ok=1;			    				
			}else ok=0;
		} 		
	}//fin aceptationDemande()
	
	
	/** Methode qui supprime la demande **/
	private void supprimerDemande() throws IOException 
	{
		if(_in.read(charCur, 0, 1) != -1)
		{		
			int ok;
			if(charCur[0]=='1')// resultat1 supprimerDemande
			{					    				
				ok=1;			    				
			}else ok=0;
		}  
	}//fin supprimerDemande()
	
	/** Methode qui supprime la demande **/
	private void actualiseListeMessages() throws IOException 
	{
		String var="";String[]tab1;String[] tab2;
		while(_in.read(charCur, 0, 1) != -1)
		{		
			if (charCur[0] != '\u0000'){						        	
	            var=var+charCur[0];						
	        }
			else{	
				if(var!=""){
					tab1=var.split(";");
					for(int i=0;i<tab1.length;i++){
						tab2=tab1[i].split(",");
						Message mess=new Message(tab2[0],tab2[1],tab2[2]);
						messages.add(mess);
					}
				}
				break;
			}							
		}  
	}//fin supprimerDemande()
	
	
	public ArrayList<Message> getMessages() {
		return messages;
	}


	public void setMessages(ArrayList<Message> messages) {
		this.messages = messages;
	}


	/** Methode **/
	public void envoieMessage(String mail,String message) throws IOException
	{
			String mess="M"+mail+";"+message+"\u0000";
   			comm.getOutputStream().write(mess.getBytes());
   			comm.getOutputStream().flush(); 
	}//fin envoieMessage()
	
	/**
	 * Méthode qui supprime un message lu par le client
	 * @throws IOException 
	 */
	public void supprimerMessage(String message) throws IOException{
		String mess="G"+message+"\u0000";
		comm.getOutputStream().write(mess.getBytes());
		comm.getOutputStream().flush(); 
	}
	
	
	/** Methodes get et set**/
	public int getAction() {
		return action;
	}

	public void setAction(int action) {
		this.action = action;
	}

	public ArrayList<Conversation> getConversations() {
		return conversations;
	}

	public void setConversations(ArrayList<Conversation> conversations) {
		this.conversations = conversations;
	}

	public ArrayList<String> getAmis() {
		return amis;
	}
	
	public void setAmis(ArrayList<String> amis) {
		this.amis = amis;
	}
	
	public String getEmail() {
		return email;
	}
	
	public void setEmail(String email) {
		this.email = email;
	}

	public void setMdp(String x) {
		this.mDp=x;
	}
	
	public int getExiste(){
		return existe;
	}
	
	public void setExiste(int ex) {
		existe=ex;
	}
	
	public int getDejaAmi(){
		return dejaAmi;
	}
	
	public void setDejaAmi(int ex) {
		dejaAmi=ex;
	}
	
	public int getExiste2(){
		return existe2;
	}
	
	public void setExiste2(int ex) {
		existe2=ex;
	}
	
	public String getDemandeur() {
		return demandeur;
	}
	
	public boolean getDemandeurFini() {
		return demandeurFini;
	}
	
	public int getPasEncoreDemande() {
		return pasEncoreDemande;
	}
	
	public Socket getComm() {
		return comm;
	}

	public void setComm(Socket comm) {
		this.comm = comm;
	}

	public CommunicationClientEnvoie getComE() {
		return comE;
	}

	public void setComE(CommunicationClientEnvoie comE) {
		this.comE = comE;
	}

	public void setfName(String prenom2) {
		fName=prenom2;
	}

	public void setNam(String nom2) {
		nam=nom2;
	}
	
	public HashMap<String, String> getAmi() {
		return statuts;
	}

	public String getStatut() {
		return statut;
	}

	public void setStatut(String statut) {
		this.statut = statut;
	}
	public String getPseudo() {
		return pseudo;
	}

	public void setPseudo(String pseudo) {
		this.pseudo = pseudo;
	}

	public ArrayList<String> getAmisDeco() {
		return amisDeco;
	}

	public void setAmisDeco(ArrayList<String> amisDeco) {
		this.amisDeco = amisDeco;
	}

	public HashMap<String, String> getStatuts() {
		return statuts;
	}

	public void setStatuts(HashMap<String, String> statuts) {
		this.statuts = statuts;
	}

	public HashMap<String, String> getPseudos() {
		return pseudos;
	}

	public void setPseudos(HashMap<String, String> pseudos) {
		this.pseudos = pseudos;
	}
	//fin methodes get et set

	
}//fin Classe CommunicationClient 

